﻿using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using System.IO.IsolatedStorage;

namespace ResourcesManager
{
    public struct UriEx
    {
        public Uri uri;
        public object sender;        
        public UriEx(Uri thisUri, object thisSender)
        {
            uri = thisUri;
            sender = thisSender;
        }
    }
    /// <summary>
    /// This class represent main game resources downloader.
    /// </summary>
    public static class ResourcesManager
    {
        /// <summary>
        /// This property is used for any control that need resources. This resources will be download before scene is loaded.
        /// </summary>
        public static readonly DependencyProperty LoadResourcesProperty = DependencyProperty.RegisterAttached(
                 "LoadResources",                  //Name of the property
                 typeof(string),             //Type of the property
                 typeof(ResourcesManager),   //Type of the provider of the registered attached property
                 null);                           //Callback invoked in case the property value has changed

        public static void SetLoadResources(DependencyObject obj, string res)
        {
            obj.SetValue(LoadResourcesProperty, res);
        }

        public static string GetLoadResources(DependencyObject obj)
        {
            return (string)obj.GetValue(LoadResourcesProperty);
        }
        private static int actualDownload = 0;
        /// <summary>
        /// Download asynchronous one resource.
        /// </summary>
        /// <param name="uri">Uri of the file</param>
        /// <param name="handler">Handler what will be raise after download</param>
        /// <param name="progressChanged">Handler that will be raise in download process</param>
        
        public static void DownloadFile(UriEx uri, DownloadComplete handler, Downloading progressChanged)
        {
            StreamResourceInfo info = Application.GetResourceStream(new Uri("HOG;component/" + uri.uri.OriginalString, UriKind.RelativeOrAbsolute));
            if (info != null)//file is on the stream                           
                handler(uri.sender,info.Stream);            
            else
            {
                WebClient client = new WebClient();                
                client.OpenReadCompleted += new OpenReadCompletedEventHandler((sender, arg) => 
                        {
                            if (arg.Error == null)
                            {
                                SaveStreamToResources(arg.Result,arg.UserState as Uri);                                
                                handler(uri.sender, arg.Result);
                            }
                            else
                                handler(uri.sender, null);
                        });
                client.OpenReadAsync(uri.uri,uri.uri);
                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler((obj, arg) => 
                        {
                            string fileName = ((Uri)arg.UserState).OriginalString;
                            if(progressChanged != null)
                                progressChanged(fileName,arg.ProgressPercentage);
                        });
            }
        }
        /// <summary>
        /// Class that download many files.
        /// </summary>
        /// <param name="uriList">List of files do download</param>
        /// <param name="downloadCompleteEvent">Handler for completed one download process</param>
        /// <param name="downloadingProgress">Handler for notify changes</param>
        /// <param name="completeDownloads">Handler for complete all download process</param>
        public static void DownloadFiles(UriEx[] uriList,DownloadComplete downloadCompleteEvent,Downloading downloadingProgress,DownloadsComplete completeDownloads)
        {            
            if (uriList.Length > 0)
            {
                actualDownload++;
                DownloadFile(uriList[actualDownload-1], (sender,stream) =>
                    {                        
                        if (stream != null)
                        {                            
                            if (actualDownload < uriList.Length)//if some download are ready to download
                            {
                                if (downloadCompleteEvent != null)
                                    downloadCompleteEvent(sender,stream);
                                DownloadFiles(uriList, downloadCompleteEvent, downloadingProgress, completeDownloads);
                            }
                            else //if Resources Manager download all data                            
                            {
                                actualDownload = 0;//reset of download list                                                                                                                            
                                if(downloadCompleteEvent != null)//call method
                                    downloadCompleteEvent(sender,stream);
                                if (completeDownloads != null)
                                    completeDownloads();                                
                            }                            
                        }
                        else
                            MessageBox.Show("Nie udało się pobrać pliku!");
                    },downloadingProgress);                
            }
        }
        /// <summary>
        /// Download class for image.
        /// </summary>
        /// <param name="uri">Uri of this image</param>
        /// <returns>Image source what can be binded for Image controls</returns>
        public static ImageSource DownloadImage(Uri uri)
        {            
            return DownloadBitmapImage(uri);
        }
        public static BitmapImage DownloadBitmapImage(Uri uri)
        {
            BitmapImage bmp = null;
            Stream stream = Application.GetResourceStream(uri).Stream;
            if (stream != null)
            {
                bmp = new BitmapImage();
                bmp.SetSource(stream);
            }
            else            
            {
                bmp = new BitmapImage(uri);//load from clientBin
            }
            return bmp;
        }
        private static void SaveStreamToResources(Stream stream,Uri fileName)
        {
            try
            {
                string orginalFileName = fileName.OriginalString;
                IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
                if (!isf.FileExists(orginalFileName) && isf.AvailableFreeSpace > stream.Length)
                {
                    isf.CreateDirectory(Path.GetDirectoryName(orginalFileName));
                    IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(orginalFileName, FileMode.Create, isf);
                    using (StreamWriter sw = new StreamWriter(isfs))
                    {
                        sw.Write(stream);
                        sw.Close();
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Error while save resources to stream. Orginal message: " + e.Message);
            }
        }
    }
}
